package org.example.controller;

import org.example.annotation.LoginCheck;
import org.example.domain.Comment;
import org.example.domain.DiscussPost;
import org.example.domain.User;
import org.example.kafka.DiscussPostEvent;
import org.example.kafka.Event;
import org.example.kafka.MessageProducer;
import org.example.service.imp.*;
import org.example.util.CommonParam;
import org.example.util.HutoolUtil;
import org.example.util.SensitivityCodeFilter;
import org.example.util.UserThreadLocalUtil;
import org.example.vo.CommentVO;
import org.example.vo.IndexPageVO;
import org.example.vo.LimitPageVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import java.sql.Date;
import java.util.*;

@Controller
@RequestMapping("/discussPost/")
public class DiscussPostController {
    @Autowired
    private UserThreadLocalUtil userThreadLocalUtil;
    @Autowired
    private DiscussServiceImp discussServiceImp;
    @Autowired
    private HutoolUtil hutoolUtil;
    @Autowired
    private SensitivityCodeFilter sensitivityCodeFilter;
    @Autowired
    private UserServiceImp userServiceImp;
    @Autowired
    private CommentServiceImp commentServiceImp;
    @Autowired
    private LikeServiceImp likeServiceImp;
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private ElasticSearchServerImp elasticSearchServerImp;
    private Logger logger = LoggerFactory.getLogger(DiscussPostController.class);
    @Autowired
    private MessageProducer messageProducer;
    @Value("${server.servlet.context-path}")
    private String contextPath;
    @LoginCheck
    @PostMapping("save")
    @ResponseBody
    public String save(DiscussPost discussPost){
        if (discussPost == null){
             logger.info("帖子保存出现异常，帖子对象为null");
             return "0";
        }
        if (hutoolUtil.stringIsEmpty(discussPost.getTitle()) || hutoolUtil.stringIsEmpty(discussPost.getContent())){
            return "0";
        }
        //老师这里处理了一个前端如果传过来一个标签这里需要做一个转化 前端用utext  <> >>  lt;gt;
        StringBuilder title = new StringBuilder(discussPost.getTitle());
        StringBuilder content = new StringBuilder(discussPost.getContent());
        sensitivityCodeFilter.filter(title);
        sensitivityCodeFilter.filter(content);
        discussPost.setTitle(title.toString());
        discussPost.setContent(content.toString());

        User user = userThreadLocalUtil.get();
        discussPost.setUserId(user.getId());
        discussPost.setCreateTime(new Date(System.currentTimeMillis()));

        //这里采用kafka消息异步处理  需要存储elasticsearch和mysql中
        DiscussPostEvent event = new DiscussPostEvent();
        event.setTopic(CommonParam.KAFKA_TOPIC_DISCUSS_POST);
        event.setDiscussPost(discussPost);
        event.setPublishUser(user);

        int i = messageProducer.sendToEs(event);
//        int i = discussServiceImp.saveOne(discussPost);
        return i+"";
    }

    /**
     *
     * 这个接口有点问题  不想弄了 好难受  以后写完必须要检测好在做下面的功能
     * @param id
     * @param curr
     * @param model
     * @return
     */
    @LoginCheck
    @GetMapping("detail/{id}")
    public String detail(@PathVariable("id") int id,@RequestParam(value = "curr",required = false) Integer curr, Model model){
        if (id<=0){
            throw new RuntimeException("用户不存在");
        }
        //当前用户是否点赞
        User user2 = userThreadLocalUtil.get();
        int id3 = user2.getId();
        boolean like = likeServiceImp.currUserIsLike(1, id, id3);
        int likeCount =likeServiceImp.getLikeCount(1,id);
        model.addAttribute("discussLikeStatus",like);
        model.addAttribute("discussLikeCount",likeCount);
        //当前页面的评论数量
        int commentCount = 0;
        //获取帖子 和 发布贴子的用户
        DiscussPost discussPost = discussServiceImp.searchById(id);
        User user = userServiceImp.searchById(discussPost.getUserId());
        model.addAttribute("discuss",discussPost);
        model.addAttribute("relationUser",user);
        //获取帖子的评论 需要做分页  包括帖子的评论 和 评论的评论
        if (curr == null || curr<=0) curr = 1;
        //获取当前帖子的一级评论的个数
        int topCommentCount = commentServiceImp.searchCount(1, discussPost.getId(), 0);
        //获取分页参数
        LimitPageVO limitPageVO = hutoolUtil.limitPage(curr, CommonParam.DEFAULT_COMMENT_LIMIT, topCommentCount);
        //先获取一级评论
        List<Comment> commentList = commentServiceImp.searchByFilterCondition(discussPost.getId(), 1, 0, (limitPageVO.getCurrent()-1)*CommonParam.DEFAULT_COMMENT_LIMIT, CommonParam.DEFAULT_COMMENT_LIMIT);
        if (commentList.size()<=0){
            //不存在一级评论  那 子评论更加没有了
            model.addAttribute("noComment",true);
            model.addAttribute("type",discussPost.getType());
            model.addAttribute("status",discussPost.getStatus());
            //权限设置
            SecurityContext context = SecurityContextHolder.getContext();
            Authentication authentication = context.getAuthentication();
            List<GrantedAuthority> authorities = (List<GrantedAuthority>)authentication.getAuthorities();
            //目前我们用户就一个权限所以
            GrantedAuthority grantedAuthority = authorities.get(0);
            String authority = grantedAuthority.getAuthority();
            model.addAttribute("authority",authority);
            return "site/discuss-detail";
        }
        List<CommentVO> top = commentServiceImp.changes(commentList);
        commentCount = top.size();
        List<List<CommentVO>> oneLevelComment = new ArrayList<>();
        List<List<CommentVO>> towLevelComment = new ArrayList<>();
        //获取一级评论的子评论  子评论也有子评论  子评论的子评论也有子评论 .......    是一个递归   好麻烦啊 我就不递归了以后用到在想  这里就做两次评论(就是两个循环就行了)
        for (CommentVO temp : top){
            int id1 = temp.getComment().getId();
            List<Comment> commentList1 = commentServiceImp.searchByFilterCondition(discussPost.getId(), 2, id1, 0, Integer.MAX_VALUE);
            if (commentList1.size()>0) {
                List<CommentVO> changes = commentServiceImp.changes(commentList1);
                oneLevelComment.add(changes);
                commentCount = commentCount + changes.size();
            }else {
                List<CommentVO> zero = new ArrayList<>();
                oneLevelComment.add(zero);
                towLevelComment.add(zero);
                continue;
            }
            List<Comment> tempTowLevelComment = new ArrayList<>();
            //获取一级评论中所有的二级评论
            i2:for (int i =0;i<commentList1.size();i++){

                int id2 = commentList1.get(i).getId();
                List<Comment> commentList2 = commentServiceImp.searchByFilterCondition(discussPost.getId(), 2, id2, 0, Integer.MAX_VALUE);
                if (commentList2.size()<=0) continue i2;
                tempTowLevelComment.addAll(commentList2);
            }
            commentCount = commentCount+ tempTowLevelComment.size();
            List<CommentVO> changes = commentServiceImp.changes(tempTowLevelComment);
            for(int i =0;i<changes.size();i++){
                CommentVO commentVO = changes.get(i);
                Comment comment = commentServiceImp.searchById(commentVO.getComment().getTargetId());
                User user1 = userServiceImp.searchById(comment.getUserId());
                commentVO.setReplyUser(user1);
            }
            towLevelComment.add(changes);
        }
        model.addAttribute("commentCount",commentCount);
        model.addAttribute("topComment",top);
        model.addAttribute("oneLevelComment",oneLevelComment);
        model.addAttribute("twoLevelComment",towLevelComment);
        limitPageVO.setPath("/discussPost/detail/");
        model.addAttribute("limitParam",limitPageVO);
        model.addAttribute("type",discussPost.getType());
        model.addAttribute("status",discussPost.getStatus());
        //获取当前用户的权限
        //权限设置
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        List<GrantedAuthority> authorities = (List<GrantedAuthority>)authentication.getAuthorities();
        //目前我们用户就一个权限所以
        GrantedAuthority grantedAuthority = authorities.get(0);
        String authority = grantedAuthority.getAuthority();
        model.addAttribute("authority",authority);
        return "site/discuss-detail";
    }
    @RequestMapping("search")
    public String search(String content,@RequestParam(required = false) Integer current,Model model){
        if (hutoolUtil.stringIsEmpty(content)){
            model.addAttribute("result",null);
            return "index";
        }
        if (current==null || current<=0)current =1;
        //如何分页超过总的分页数 返回null  如何没有数据返回null
        IndexPageVO search = elasticSearchServerImp.search(content,current,5);
        if (search==null){
            model.addAttribute("result",null);
            return "index";
        }
        //获取帖子对应的点赞 回帖数量
        List<DiscussPost> discussPost = search.getDiscussPost();
        if (discussPost!=null && discussPost.size()>0){
            List<Integer> discussLike = new ArrayList<>();
            for (int i = 0;i<discussPost.size();i++){
                Integer likeCount = likeServiceImp.getLikeCount(1, discussPost.get(i).getId());
                discussLike.add(likeCount);
            }
            model.addAttribute("discussLike",discussLike);
        }

        search.getLimitPageVO().setPath("/discussPost/search?content="+content);
        model.addAttribute("result",search);
        return "index";
    }
    @PostMapping("top")
    @ResponseBody
    public Integer top(int id){
        int i = discussServiceImp.updateType(id, 1);
        //因为我们的搜索是利用es处理的 需要数据同步一下 额 这个请求是将帖子顶置 dao处理了 后面的逻辑不是这个请求需要特别处理 我们可以异步线程处理 利用kafka
        DiscussPost discussPost = discussServiceImp.searchById(id);
        DiscussPostEvent event = new DiscussPostEvent();
        event.setTopic(CommonParam.KAFKA_TOPIC_UPDATE_DISCUSS);
        event.setDiscussPost(discussPost);
        messageProducer.sendToEs(event);

        return i;

    }

    @PostMapping("digest")
    @ResponseBody
    public Integer digest(int id){
        int i = discussServiceImp.updateStatus(id, 1);
        //因为我们的搜索是利用es处理的 需要数据同步一下 额 这个请求是将帖子顶置 dao处理了 后面的逻辑不是这个请求需要特别处理 我们可以异步线程处理 利用kafka
        DiscussPost discussPost = discussServiceImp.searchById(id);
        DiscussPostEvent event = new DiscussPostEvent();
        event.setTopic(CommonParam.KAFKA_TOPIC_UPDATE_DISCUSS);
        event.setDiscussPost(discussPost);
        messageProducer.sendToEs(event);
        return i;
    }
    @PostMapping("delete")
    @ResponseBody
    public Integer delete(int id){
        int i = discussServiceImp.updateStatus(id, 2);
        //因为我们的搜索是利用es处理的 需要数据同步一下 额 这个请求是将帖子顶置 dao处理了 后面的逻辑不是这个请求需要特别处理 我们可以异步线程处理 利用kafka
        messageProducer.deleteDiscuss(CommonParam.KAFKA_TOPIC_DELETE_DISCUSS,id+"");
        return i;
    }

    /**
     * 热贴排名 跟主页的展示差不多  不过排序的形式是按照score排名的
     * 不过帖子score的计算需要一些处理
     * 帖子的分数 受到点赞 关注 评论 的影响   这里影响是很频繁的 我们需要按时去计算(每隔一段时间 处理改变的帖子分数)  这个可以用一个定时任务(这里我们跟着老师用quartz)
     *
     * @param current
     * @param model
     * @return
     */
    @GetMapping("/hotRank")
    public String hotRank(@RequestParam(value = "current",required = false) Integer current,Model model){
        IndexPageVO indexPageVO = null;
        if (current == null){
            indexPageVO = discussServiceImp.searchHotDiscuss(CommonParam.DEFAULT_PAGE, CommonParam.DEFAULT_LIMIT);
        }else {
            indexPageVO = discussServiceImp.searchHotDiscuss(current, CommonParam.DEFAULT_LIMIT);
        }
        indexPageVO.getLimitPageVO().setPath("/discussPost/hotRank");
        List<DiscussPost> discussPost = indexPageVO.getDiscussPost();
        if (discussPost!=null && discussPost.size()>0){
            List<Integer> discussLike = new ArrayList<>();
            for (int i = 0;i<discussPost.size();i++){
                Integer likeCount = likeServiceImp.getLikeCount(1, discussPost.get(i).getId());
                discussLike.add(likeCount);
                model.addAttribute("discussLike",discussLike);
            }
        }
        model.addAttribute("result",indexPageVO);
        model.addAttribute("hot","hot");
        return "index";

    }

}
